/**
    ATClab - scriptable Air Traffic Control simulations.
    Copyright (C) 2010 openatclab@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

#ifdef WIN32
	#pragma warning(disable:4786)
#endif

//#include "vld.h"	// visual leak detector

#include "logging/logger.h"
#include "parser/xmlhandler.h"
#include "parser/xmlreader.h"
#include "pact/experiment.h"
#include "pact/presenter.h"
#include "performance/builder.h"
#include "performance/exception.h"
#include "performance/factory.h"
#include "performance/parser.h"
#include "version.h"

#include <fstream>

#include <qapplication.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qmessagebox.h>


#include <xercesc/util/PlatformUtils.hpp>

#define QT3_SUPPORT

int critical( const QString & );

int main( int argc, char **argv ) {

	//
	// create application instance
	//

	QApplication app( argc, argv );
	if ( 1 == app.argc() ) {
		QFileInfo fi( *argv );

		QString version = QString("ATCLab Version: %1").arg(ATC_VERSION.c_str());
		QString usage = QString("usage: %1 <experiment_script>").arg(fi.fileName());
		QString displayText = version + "\n\n" + usage;

		return critical(displayText);
	}

	QFile script( app.argv()[ app.argc() - 1 ] );
	if ( !script.exists() ) {
		return critical(
			QString( "cannot open experiment script '%1'" ).arg( script.name() )
		);
	}

	

	//
	// initialize logging
	// 
	
    logging::Logger::set_name( std::string(argv[argc -1]).append(".log") );


	//
	// load performance data
	//

	QFileInfo performance_file( QDir(app.applicationDirPath()), "acperf.txt" );
	//const char *performance_file = "acperf.txt";

	std::ifstream ifs( performance_file.absFilePath().local8Bit() );
	if ( ! ifs ) {
		return critical( QString
			( "cannot open performace data [%1]" ).arg( performance_file.absFilePath() ) 
		);
	}

	performance::Builder performance_builder;
	performance::Parser performance_parser( ifs, performance_builder );

	try {
		performance_parser.parse();
	}
	catch ( performance::performance_data_error &ex ) {
		return critical( QString
			( "performance parsing errors: %1" ).arg( ex.what() )
		);
	}

	performance::Factory::initialize( performance_builder.data() );



	//
	// load experiment script
	//

    /*try {
        xercesc::XMLPlatformUtils::Initialize();
    } catch (const xercesc::XMLException &ex) {
        char *msg = xercesc::XMLString::transcode(ex.getMessage());
        QString message = QString("unable to initialize XML platform utils: %1").arg(msg);
        xercesc::XMLString::release(&msg);
        return critical(message);
    }*/


	pact::Experiment exp;
	xml::XMLHandler handler( exp, logging::Logger::instance() );
	xml::XMLReader experiment_parser;
	experiment_parser.setSAX2Handler( &handler );

	try	{
		experiment_parser.parse( app.argv()[ app.argc() - 1 ] );

		if ( ! exp.validate() ) {
			return critical(QString(
				"invalid experiment script (see log for details)"
			));
		}
	}
	catch( std::runtime_error& ex ) {
		return critical( ex.what() );
	}

	//
	// run experiment
	//
	int retValue = 0;

	try {
		pact::Presenter* presenter = pact::Presenter::instance();
		app.setMainWidget( presenter );
		presenter->setExperiment( &exp );
		presenter->showFullScreen();
		presenter->start();

		retValue = app.exec();

		presenter->destroy();
	}
	catch( std::runtime_error& ex ) {
		return critical( ex.what() );
	}

	//
	// clean up
	//

	performance::Factory::destroy();

	logging::Logger::destroy();

	return retValue;
}

int critical( const QString &msg ) {
	return QMessageBox::critical(
			0
		  ,	"ATC-Lab Presentation Module"
		  ,	msg
		  ,	QMessageBox::Ok | QMessageBox::Default | QMessageBox::Escape
		  ,	Qt::NoButton
		  ,	Qt::NoButton
	);
}
